package com.xl.utils.file;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Author:XueH
 * @Description:
 * @Date:Created in 14:42 2022/8/23
 * @Modified By:
 */
@Slf4j
@Data
public class FileUtil {

	/**
	 * 根据文件全路径判断文件是否存在
	 *
	 * @param path 全路径
	 * @return
	 */
	public static boolean exist(String path) {
		File file = getFile(path);
		return file.exists();
	}

	/**
	 * 判断文件是否存在
	 * 存在返回文件
	 *
	 * @param path 根据文件全路径判断文件是否存在
	 * @return
	 */
	public static File existRetFile(String path) {
		File file = getFile(path);
		if (file.exists()) {
			return file;
		}
		return null;
	}

	/**
	 * 输入路径判断文件夹是否存在 不存在则进行创建
	 *
	 * @param path
	 */
	public static void noExistCreateDir(String path) {
		File file = getFile(path);
		if (!file.exists() && file.mkdir()) {
			log.info("文件夹创建成功,创建位置:{}", JSONUtil.toJsonStr(path));
		}
	}

	/**
	 * 输入路径判断文件夹是否存在 不存在则进行创建
	 * 该方法支持逐级创建文件夹
	 *
	 * @param path
	 */
	public static void noExistCreateDirs(String path) {
		File file = getFile(path);
		if (!file.exists() && file.mkdirs()) {
			log.info("文件夹逐级创建成功,创建位置:{}", JSONUtil.toJsonStr(path));
		}
	}

	/**
	 * 输入路径判断文件是否存在 不存在则进行创建
	 *
	 * @param path
	 */
	public static void noExistCreateFile(String path) {
		File file = getFile(path);
		try {
			if (!file.exists() && file.createNewFile()) {
				log.info("文件创建成功,创建位置:{}", JSONUtil.toJsonStr(path));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static File writeTempFile(String str, String prefix) {
		File tempFile = null;
		FileOutputStream fos = null;
		try {
			tempFile = File.createTempFile(prefix, ".txt");
			fos = new FileOutputStream(tempFile, true);
			//true表示在文件末尾追加
			fos.write(str.getBytes());
		} catch (IOException e) {
			log.error("writeTempFile IOException", e);
		} finally {
			try {
				if (fos != null) {
					fos.close();
				}
			} catch (IOException e) {
			}
		}
		return tempFile;
	}

	/**
	 * 判断文件夹存在
	 * 获取文件夹里面所有的文件
	 * 不递归获取
	 *
	 * @param path
	 */
	public static List<File> existDirGetChildFiles(String path) {
		return getDirFiles(path, false);
	}

	/**
	 * 判断文件夹存在
	 * 获取文件夹里面所有的文件
	 * recursion 为false 不递归获取 为true递归获取文件夹下的文件
	 *
	 * @param path
	 * @param recursion
	 * @return
	 */
	public static List<File> existDirGetChildFiles(String path, boolean recursion) {
		return getDirFiles(path, recursion);
	}


	private static List<File> getDirFiles(String path, boolean recursion) {
		File dirFile = existRetFile(path);
		if (Objects.isNull(dirFile) || dirFile.isFile()) {
			return new ArrayList();
		}
		File[] childrenFiles = dirFile.listFiles();
		if (ArrayUtil.isEmpty(childrenFiles)) {
			return new ArrayList();
		}
		List<File> files = new ArrayList<>();
		for (File file : childrenFiles) {
			if (file.isFile()) {
				files.add(file);
			} else {
				if (!recursion) {
					continue;
				} else {
					List<File> fileList = getDirFiles(file.getPath(), recursion);
					if (!CollectionUtils.isEmpty(fileList)) {
						files.addAll(fileList);
					}
				}
			}
		}
		return files;
	}

	/**
	 * 根据path得到文件（File）
	 *
	 * @param path
	 * @return
	 */
	private static File getFile(String path) {
		File file = new File(path);
		return file;
	}

	/**
	 * 批量删除文件
	 *
	 * @param filePaths
	 */
	public static void deleteFilesByPathList(List<String> filePaths) {
		if (CollectionUtils.isEmpty(filePaths)) {
			return;
		}
		for (String filePath : filePaths) {
			File file = new File(filePath);
			file.delete();
		}
	}


	/**
	 * 批量删除文件
	 *
	 * @param files
	 */
	public static void deleteFiles(List<File> files) {
		if (CollectionUtils.isEmpty(files)) {
			return;
		}
		for (File file : files) {
			file.delete();
		}
	}

	/**
	 * 转换文件大小
	 */
	public static String formatFileSize(long fileS) {
		DecimalFormat df = new DecimalFormat("#.00");
		String fileSizeString = "";
		if (fileS == 0) {
			fileSizeString = "0.00B";
		} else {
			if (fileS < 1024) {
				fileSizeString = df.format((double) fileS) + "B";
			} else if (fileS < 1048576) {
				fileSizeString = df.format((double) fileS / 1024) + "KB";
			} else if (fileS < 1073741824) {
				fileSizeString = df.format((double) fileS / 1048576) + "MB";
			} else {
				fileSizeString = df.format((double) fileS / 1073741824) + "GB";
			}
		}

		return fileSizeString;
	}


	/**
	 * 计算文件的MD5值
	 *
	 * @param file
	 * @return
	 */
	public static String getFileMD5(File file) {
		if (!file.isFile()) {
			return null;
		}
		MessageDigest digest = null;
		FileInputStream in = null;
		byte[] buffer = new byte[8192];
		int len;
		try {
			digest = MessageDigest.getInstance("MD5");
			in = new FileInputStream(file);
			while ((len = in.read(buffer)) != -1) {
				digest.update(buffer, 0, len);
			}
			return new BigInteger(1, digest.digest()).toString(16);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	public static void downloadFile(String filePath, String url, String packageName, String fileMD5) {
		log.info("网管上传的文件为-{}", packageName);
		File f = new File(filePath);
		if (!f.exists()) {
			f.mkdirs();
		}
		String fullPath = filePath + "/" + packageName;
		File file = new File(fullPath);
		if (!(file.exists() && fileMD5.equals(getFileMD5(file)))) {
			//从网管下载
			downloadFromNetshark(url, fullPath);
			log.info("mpu下载文件成功-{}", fullPath);
		}
	}


	public static void downloadFromNetshark(String url, String fullPath) {
		try {
			// 构造URL
			URL u = new URL(url);
			// 打开连接
			URLConnection conn = u.openConnection();
			int fileSize = conn.getContentLength();

			//1K的数据缓冲
			byte[] buffer = new byte[1024];
			// 读取到的数据长度
			int length, curSize = 0, readNum = 0;

			try (InputStream inStream = conn.getInputStream(); FileOutputStream fileOutputStream = new FileOutputStream(fullPath, false)) {
				//false：覆盖文件,true:在原有文件后追加
				fileSize /= 100;  //百分比
				while ((length = inStream.read(buffer)) != -1) {
					fileOutputStream.write(buffer, 0, length);
					++readNum;
					curSize += length;
					if (readNum % 100 == 0) {
						log.info("文件下载进度：======== {}, {}%", curSize, curSize / fileSize);
					}
				}
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
